package com.zhangshuo.common.shiro;

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.cache.Cache.ValueWrapper;

/**
 * Created by Administrator on 2017/6/2 0002.
 * 自定义的密码比对器 在父类的基础上加入最大错误次数，将错误次数记入缓存中，如果失败，则加1 ，如果正常登陆，则清空记录
 */
public class RetryLimitCredentialsMatcher extends HashedCredentialsMatcher implements InitializingBean {
    Logger logger = LoggerFactory.getLogger(RetryLimitCredentialsMatcher.class);
    private static final String DEFAULT_RETRY_LIMIT_CACHE_NAME = "retryLimitCache";

    private CacheManager cacheManager;
    private String retryLimitCacheName;
    private Cache cache;

    /**
     * 在这里不能直接赋值 ，需要将所有参数都 注入后才可以用
     * @param cacheManager
     * @param retryLimitCacheName
     *
     */
    public RetryLimitCredentialsMatcher(CacheManager cacheManager, String retryLimitCacheName) {
        this.cacheManager = cacheManager;
        this.retryLimitCacheName = retryLimitCacheName;
        this.cache = this.cacheManager.getCache(this.retryLimitCacheName);
    }

    /**
     * 使用默认的缓存名称
     *
     * @param cacheManager
     */
    public RetryLimitCredentialsMatcher(CacheManager cacheManager) {
        this(cacheManager, DEFAULT_RETRY_LIMIT_CACHE_NAME);
    }

    private RetryLimitCredentialsMatcher() {
    }


    public CacheManager getCacheManager() {
        return cacheManager;
    }

    public void setCacheManager(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }

    public String getRetryLimitCacheName() {
        return retryLimitCacheName;
    }

    public void setRetryLimitCacheName(String retryLimitCacheName) {
        this.retryLimitCacheName = retryLimitCacheName;
    }

    /**
     * 用户是否通过验证
     *
     * @param token
     * @param info
     * @return
     */
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        String username = ((UsernamePasswordToken) token).getUsername();

        AtomicInteger retryCount ;
        if (cache.get(username) == null){
            retryCount = new AtomicInteger(0);
            cache.put(username, retryCount);
        }else{
            retryCount = (AtomicInteger) (cache.get(username));
        }


        if (retryCount.incrementAndGet() > 5) {
            logger.warn("用户: {} 的最大错误次数达到 {} 次，锁定帐号 {} 分钟", username, 5, 30);
            throw new ExcessiveAttemptsException("密码输入次数达到最大限度 锁定帐号");
        }
        cache.put(username,retryCount);

        boolean matcher = super.doCredentialsMatch(token, info);

        //如果匹配，则清空cache
        if (matcher) {
            cache.remove(username);
        }

        return matcher;

    }

    /**
     * 在属性完全设置完成后再做剩余的操作
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        //this.cache = this.cacheManager.getCache(this.retryLimitCacheName);
    }
}
